﻿@implements IDisposable
@using Microsoft.JSInterop
@using Radzen.Blazor.Rendering
@inject IJSRuntime JSRuntime

@foreach (var dialog in dialogs)
{
    <DialogContainer @key=@dialog Dialog=@dialog ShowMask=@(dialog==dialogs.LastOrDefault()) />
}

@if (isSideDialogOpen)
{
    <aside
        class="@GetSideDialogCssClass()"
        tabindex="@(isSideDialogOpen ? "0" : "-1")"
        style="@GetSideDialogStyle()"
        aria-labelledby="rz-dialog-side-label"
        >
        @if (sideDialogOptions.ShowTitle)
        {
            <div class="rz-dialog-side-titlebar">
                <div class="rz-dialog-side-title" style="display: inline" id="rz-dialog-side-label">
                    @if (sideDialogOptions.TitleContent != null)
                    {
                        @sideDialogOptions.TitleContent(Service)
                    }
                    else if (!string.IsNullOrEmpty(sideDialog?.Title))
                    {
                        @sideDialog.Title
                    }
                    else
                    {
                        @sideDialogOptions.Title
                    }
                </div>
                @if (sideDialogOptions.ShowClose)
                {
                    <a id="@(sideDialogOptions.GetHashCode() + "cl")" aria-label="@CloseSideDialogAriaLabel" @onclick:preventDefault="true" class="rz-dialog-side-titlebar-close" @onclick="@(_ => Service.CloseSide(null))" role="button" tabindex="@sideDialogOptions.CloseTabIndex">
                        <span class="notranslate rzi rzi-times"></span>
                    </a>
                }
            </div>
        }
        <div class="@SideDialogContentCssClass" style="@sideDialogOptions.Style">
            @sideDialogContent
        </div>
    </aside>
    @if (dialogs.Count == 0 && sideDialogOptions.ShowMask)
    {
        @if (sideDialogOptions.CloseDialogOnOverlayClick)
        {
            <div @onclick="@Service.CloseSide" class="rz-dialog-mask"></div>
        }
        else
        {
            <div class="rz-dialog-mask"></div>
        }
    }
}

@code {
    string SideDialogContentCssClass
    {
        get
        {
            var baseCss = "rz-dialog-side-content";
            return string.IsNullOrEmpty(sideDialogOptions.ContentCssClass) ? baseCss : $"{baseCss} {sideDialogOptions.ContentCssClass}";
        }

    }
    [Inject] 
    DialogService Service { get; set; }

    /// <summary>
    /// Gets or sets the close side dialog aria label text.
    /// </summary>
    /// <value>The close side dialog aria label text.</value>
    [Parameter]
    public string CloseSideDialogAriaLabel { get; set; } = "Close side dialog";

    List<Dialog> dialogs = new List<Dialog>();
    bool isSideDialogOpen = false;
    RenderFragment sideDialogContent;
    SideDialogOptions sideDialogOptions;
    Dialog sideDialog;

    public async Task Open(string title, Type type, Dictionary<string, object> parameters, DialogOptions options)
    {
        dialogs.Add(new Dialog() { Title = title, Type = type, Parameters = parameters, Options = options });

        await InvokeAsync(() => { StateHasChanged(); });
    }

    public async Task Close(dynamic result)
    {
        var lastDialog = dialogs.LastOrDefault();
        if (lastDialog != null)
        {
            dialogs.Remove(lastDialog);
            if (dialogs.Count==0) await JSRuntime.InvokeAsync<string>("Radzen.closeDialog");
        }

        await InvokeAsync(() => 
        { 
            StateHasChanged(); 
        });
    }

    public void Dispose()
    {
        Service.OnOpen -= OnOpen;
        Service.OnClose -= OnClose;

        Service.OnSideOpen -= OnSideOpen;
        Service.OnSideClose -= OnSideClose;
    }

    protected override void OnInitialized()
    {
        Service.OnOpen += OnOpen;
        Service.OnClose += OnClose;

        Service.OnSideOpen += OnSideOpen;
        Service.OnSideClose += OnSideClose;
    }

    void OnSideOpen(Type sideComponent, Dictionary<string, object> parameters, SideDialogOptions options)
    {
        sideDialogOptions = options;
        
        // Create a DialogOptions from SideDialogOptions by copying common properties
        var dialogOptions = new DialogOptions()
        {
            ShowTitle = options.ShowTitle,
            ShowClose = options.ShowClose,
            Width = options.Width,
            Height = options.Height,
            Style = options.Style,
            CloseDialogOnOverlayClick = options.CloseDialogOnOverlayClick,
            CssClass = options.CssClass,
            WrapperCssClass = options.WrapperCssClass,
            ContentCssClass = options.ContentCssClass,
            CloseTabIndex = options.CloseTabIndex,
            TitleContent = options.TitleContent
        };
        
        // Create a Dialog object for the side dialog to support cascading parameter
        sideDialog = new Dialog() 
        { 
            Title = options.Title, 
            Type = sideComponent, 
            Parameters = parameters, 
            Options = dialogOptions 
        };
        
        // Wrap the content in a CascadingValue to provide the Dialog object to child components
        sideDialogContent = new RenderFragment(builder =>
        {
            // Open CascadingValue
            builder.OpenComponent<CascadingValue<Dialog>>(0);
            builder.AddAttribute(1, "Value", sideDialog);
            builder.AddAttribute(2, "IsFixed", true);
            builder.AddAttribute(3, "ChildContent", (RenderFragment)((builder2) =>
            {
                // Open the actual component
                builder2.OpenComponent(0, sideComponent);
                foreach (var parameter in parameters)
                {
                    builder2.AddAttribute(1, parameter.Key, parameter.Value);
                }
                builder2.CloseComponent();
            }));
            builder.CloseComponent(); // Close CascadingValue
        });
        isSideDialogOpen = true;
        StateHasChanged();
    }

    bool sideDialogClosing = false;

    async Task OnSideCloseAsync()
    {
        sideDialogClosing = true;

        StateHasChanged();

        await Task.Delay(300);

        isSideDialogOpen = false;
        sideDialogClosing = false;

        StateHasChanged();

        Service.OnSideCloseComplete();
    }

    void OnSideClose(dynamic _)
    {
        if (isSideDialogOpen)
        {
            InvokeAsync(OnSideCloseAsync);
        }
    }

    void OnOpen(string title, Type type, Dictionary<string, object> parameters, DialogOptions options)
    {
        Open(title, type, parameters, options).ConfigureAwait(false);
    }

    void OnClose(dynamic result)
    {
        Close(result).ConfigureAwait(false);
    }

    string GetSideDialogCssClass() => ClassList.Create("rz-dialog-side")
                                               .Add($"rz-dialog-side-position-{sideDialogOptions.Position.ToString().ToLower()}")
                                               .Add(sideDialogOptions.CssClass)
                                               .Add("rz-open", !sideDialogClosing)
                                               .Add("rz-close", sideDialogClosing)
                                               .ToString();

    string GetSideDialogStyle()
    {
        string widthStyle = string.IsNullOrEmpty(sideDialogOptions.Width) ? string.Empty : $"width: {sideDialogOptions.Width};";
        string heightStyle = string.IsNullOrEmpty(sideDialogOptions.Height) ? string.Empty : $"height: {sideDialogOptions.Height};";

        return $"{widthStyle}{heightStyle}{sideDialogOptions.Style}";
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);

        if (isSideDialogOpen)
        {
            await JSRuntime.InvokeAsync<string>("Radzen.openSideDialog", sideDialogOptions);
        }
    }
}
